package test1;

import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.*;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.List;

/**
 * @author: mornd
 * @dateTime: 2023/5/11 - 1:04
 * 自动配置 starting
 */
public class App {

    // boot 的自动配置
    public static void main2(String[] args) {
        List<String> names = SpringFactoriesLoader
                .loadFactoryNames(EnableAutoConfiguration.class, null);
        names.forEach(System.out::println);
    }

    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();
        // 不允许后面同名的 bean 覆盖前面的，boot 默认false，如果出现同名则报错
        context.getDefaultListableBeanFactory().setAllowBeanDefinitionOverriding(false);
        context.registerBean(Config.class);
        context.registerBean(ConfigurationClassPostProcessor.class);
        context.refresh();

        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }

        // spring 优先加载 @Import 导入的bean，但是后面同名的bean可以覆盖前面定义的
        System.out.println(">>>>>>>>" + context.getBean("bean1"));
        context.close();
    }

    @Import(MyImportSelector.class)
    static class Config {

        @Bean("bean1")
        @ConditionalOnMissingBean
        public Bean1 bean1() {
            return new Bean1("本项目");
        }
    }

    /**
     * 实现 ImportSelector 接口的会被容器先加载，而自身配置类中的 bean 则在其后面加载
     * 若想先加载本项目的，则实现 DeferredImportSelector 接口即可
     */
    static class MyImportSelector implements DeferredImportSelector {
        @Override
        public String[] selectImports(AnnotationMetadata importingClassMetadata) {

//            return new String[] {Config2.class.getName(), Config3.class.getName()};

            /**
             * 配置文件方式获取
             * 手动加载 spring.factories 文件，根据 key 获取 values
             * 第一个参数就是配置文件的 key 对应的 class 对象
             * 第二个参数为null，spring 会自动补充的
             */
            List<String> names =
                    SpringFactoriesLoader.loadFactoryNames(MyImportSelector.class, null);
            return names.toArray(new String[0]);
        }
    }

    @AllArgsConstructor
    @NoArgsConstructor
    @ToString
    static class Bean1 {
        String name;
    }
    @Configuration
    static class Config2 {

        @Bean("bean1")
        @ConditionalOnMissingBean
        public Bean1 bean1() {
            return new Bean1("第三方");
        }
    }

    static class Config3 {
        @Bean("bean2")
        public Bean1 bean1() {
            return new Bean1();
        }
    }

}
